menu
  Home  ==>  papers  ==>  web  ==>  asp_net  ==>  cassini_spy   

CASSINI Spy - Felix John COLIBRI.

  • abstract : a sniffing utility which captures and display all HTTP packets between the Cassini Web Server and your Browser
  • key words : ASP.NET development, CASSINI, HTTP sniffer
  • software used : Windows XP, Delphi 2006, Delphi 2005
  • hardware used : Pentium 2.800Mhz, 512 M memory, 250 G hard disc
  • scope : Delphi 8, 2005, 2006, Windows C# framework
  • level : Delphi / ASP.NET developer
  • plan :


1 - Introduction

When debugging ASP.NET applications, it is very helpful to display the content of the information exchanged between the browser (Internet Explorer) and the Web Server (CASSINI or IIS).

ASP.NET can log all kind of information, but the content of what is exchanged between the Client and the Server is not, as far as I know, available.

We first tried to use our own TCP/IP Sniffer. But since CASSINI works on localhost, the packet do not travel up to the Ethernet Driver, where the Packet Sniffer would catch them.

So the alternative we found was to build a specific tool that we will present now.




2 - How it Works

A simple descriptioin of Client / Server socket operation is the following:
  • the Server (Cassini in our case) loads, opens a Server Socket which starts listening to incoming Client for HTTP requests (port 80):

    image

  • "a" Client (Internet Explorer in our case) loads, creates a Client Socket which tries to connect to a port 80 Server (Cassini):

    image

  • the Server "accepts" the connection. Since the Server is supposed to handle many Clients, it cannot take care of the communication with all Clients at the same time. This is why is spins-off a "Server Client Socket" for each incoming Client:

    image

  • the Server sends the answer back, in one or several packets, and the Client happily communicates with his "Server Client Socket":

    image

  • the communication is closed down when either client sockets closes (or an error occurs somewhere in the network)


In the case of Cassini / Internet Explorer, the port uses is by default the HTTP port, 80. But Cassini, in its staring dialog, allows to specify the listening port. This will allow the developper to still use the standard 80 port to do bona fide HTTP work on his PC (to Google around or whatever)

image

And similarily, Internet Explorer allows us to specify a connection port in the address combo box:

image



Since we can specify both Server and Client ports, we simply place our sniffing utility in the middle, communicating with Cassini on, say, port 55, and with Internet Explorer on, say, port 81:

  • Cassini and our spy start listening:

    image

  • Internet Explorer starts, and tries to connect to port 81:

    image

  • our spy spins off a Server Client Socket which receives the Internet Explorer request:

    image

  • our spy creates a Client Socket which will now communicate with Cassini:

    image

  • this Client Socket forwards the IE request to Cassini, which spins off a Server Client Socket :

    image

  • the packets then flow between Cassini and Internet Explorer, with our spy sitting in the middle, capturing the packets and doing whatever it wants with those packets (saving them to disk, formating them and displaying them in a window etc.) :

    image



We showed Internet Explorer, our spy and Cassini on 3 different PCs. In fact, Cassini is by definition a LOCAL Server. It can only handle request from a browser on the SAME machine. So our figure should represent everything on the same PC. But the idea is the same.



To implement our spy, we simple build a Delphi application with

  • a Server Socket listening to Internet Explorer
  • the request from Internet Explorer will spin off a Server Client Socket, which will:
    • forward the request to Cassini
    • watch for Cassini's answers, and shovel them back to Internet Explorer
  • all the packets will be displayed, in different formats, in tMemos of our application



3 - Delphi Source Code

3.1 - Socket components

It is possible to use the standard Delphi tServerSocket and tClientSocket components. You may look at our Delphi Socket Architecture paper which explain how to use them, with a sample file transfer project.

We can also use our own Socket components, which were presented in the Simple Web Server paper, or any other Socket library (ICS, Indy, Synapse or whatever).

All we have to do is

  • override the generic tServer, in order to force him to use our derived Server Client Socket :

    image

  • override the generic Server Client Socket, to let it receive IE packets and transfer them the the spy Client Socket :

    image

  • override the generic tClientSocket to let him mimic IE and communicate with Cassini :

    image



For this simple utility, we will use our library. The overall UML class diagram is the following:

image

and at the bottom of the figure are our three sockets.



3.2 - The Server Client Socket

Here is the definition our our derived Server Client Socket

c_cassini_spy_server_client_socket=
    class(c_server_client_socket)
      m_on_display_cassini_spy_eventt_po_cassini_spy_display_event;
      m_cassini_portInteger;

      m_c_cassini_spy_client_socketc_cassini_spy_client_socket;

      Constructor create_server_client_socket(p_nameString;
          p_c_server_socket_refc_server_socket;
          p_cassini_portInteger); Override;

      procedure handle_can_write_dataOverride;
      procedure handle_received_dataOverride;
      procedure handle_remote_client_closedOverride;

      procedure handle_received_data_from_cassini(
          p_c_cassini_spy_client_socketc_cassini_spy_client_socket);

      Destructor DestroyOverride;
    end// c_cassini_spy_server_client_socket

where m_c_cassini_spy_client_socket is the Client Socket communicating between the Spy and Cassini

There are two interesting methods:

  • the event handler which receives packets from Internet Explorer and forwards them to Cassini using the Client Socket:

    procedure c_cassini_spy_server_client_socket.handle_received_data;
        // -- received some data from the browser
      var l_end_of_header_positionInteger;
          l_read_indexInteger;
      begin
        // -- fetch the bytes
        receive_buffered_data;

        with m_c_reception_buffer do
        begin
          if Assigned(m_on_display_cassini_spy_event)
            then
              with m_c_reception_buffer do
                m_on_display_cassini_spy_event(1,
                    f_display_buffer(m_read_indexm_write_index));

          // -- set the text to send to Cassini
          m_c_cassini_spy_client_socket.m_c_cassini_spy_text_to_send_ref:=
              m_c_reception_buffer;

          m_c_cassini_spy_client_socket.connect_tee('127.0.0.1'm_cassini_port);
        end// with p_c_byte_buffer
      end// handle_received_data

  • the symmetric handler which receives data from Cassini

    procedure c_cassini_spy_server_client_socket.handle_received_data_from_cassini(
        p_c_cassini_spy_client_socketc_cassini_spy_client_socket);
        // -- now CASSINI did send the answer

      procedure send_back(p_c_reception_bufferc_byte_buffer);
        begin
          with p_c_reception_buffer do
          begin
             // -- the server_client_socket sends back
             f_do_send_buffer(@ m_oa_byte_buffer[m_read_index], m_write_index);

             // -- move forward
             m_read_index:= m_write_index;
           end// with p_c_byte_buffer
        end// send_back

      begin // handle_received_data_from_cassini
        // -- received an answer from Cassini
        // -- forward to IE
        with p_c_cassini_spy_client_socketm_c_reception_buffer do
          if m_write_index> 0
            then begin
                if Assigned(m_on_display_cassini_spy_event)
                  then m_on_display_cassini_spy_event(2,
                      f_display_buffer(m_read_indexm_write_index));

                send_back(m_c_reception_buffer);
              end;
      end// handle_received_data_from_cassini




3.3 - The Spy Client Socket

Here is the definition our our derived Server Client Socket

c_cassini_spy_client_socket=
    class(c_client_socket)
      m_c_cassini_spy_text_to_send_refc_byte_buffer;
      m_on_cassini_spy_received_datat_po_cassini_spy_client_socket_event;

      Constructor create_cassini_spy_client_socket(p_nameString);

      procedure trace_cassini_spy_client(p_textString);

      procedure connect_to_cassini(p_serverStringp_portInteger);
      procedure handle_connected(p_c_client_socketc_client_socket);
      procedure handle_received_data(p_c_client_socketc_client_socket);
      procedure handle_remote_server_client_socket_closed(
          p_c_client_socketc_client_socket);

      Destructor DestroyOverride;
    end// c_cassini_spy_client_socket

and

  • here is the "connected" handler:

    c_cassini_spy_client_socket=
        class(c_client_socket)
          m_c_cassini_spy_text_to_send_refc_byte_buffer;
          m_on_cassini_spy_received_datat_po_cassini_spy_client_socket_event;

          Constructor create_cassini_spy_client_socket(p_nameString);

          procedure trace_cassini_spy_client(p_textString);

          procedure connect_to_cassini(p_serverStringp_portInteger);
          procedure handle_connected(p_c_client_socketc_client_socket);
          procedure handle_received_data(p_c_client_socketc_client_socket);
          procedure handle_remote_server_client_socket_closed(
              p_c_client_socketc_client_socket);

          Destructor DestroyOverride;
        end// c_cassini_spy_client_socket

  • and the method sending the data back to IE:

    procedure c_cassini_spy_client_socket.handle_received_data(
        p_c_client_socketc_client_socket);
        // -- fd_read notification was received
      var l_received_textString;
      begin
        // -- notify IE
        if Assigned(m_on_cassini_spy_received_data)
          then m_on_cassini_spy_received_data(Self);
      end// handle_received_data



3.4 - The spy Server Socket

Here is the CLASS definition:

t_po_tcp_cassini_spy_eventProcedure(p_c_cassini_spyc_cassini_spy)
    of object;

c_cassini_spy=
    class(c_basic_object)
      m_c_server_socketc_server_socket;
      m_cassini_portInteger;

      m_trace_cassini_spyBoolean;
      m_site_pathString;

      m_on_accept_tcp_cassini_spy_sockett_po_tcp_cassini_spy_event;
      m_on_display_cassini_spy_eventt_po_cassini_spy_display_event;

      Constructor create_cassini_spy(p_namep_site_pathString;
          p_cassini_portInteger);

      procedure start_cassini_spy(p_ie_portInteger);
      procedure handle_accept(p_c_server_socketc_server_socket;
          p_c_server_client_socketc_server_client_socket);
      procedure close_cassini_spy;

      Destructor DestroyOverride;
    end// c_cassini_spy

where:

  • the constructor builds the server Socket

    Constructor c_cassini_spy.create_cassini_spy(p_namep_site_pathString;
        p_cassini_portInteger);
      begin
        Inherited create_basic_object(p_name);
        m_site_path:= p_site_path;
        m_cassini_port:= p_cassini_port;

        // -- specify which c_server_client_sockt Class should be created
        m_c_server_socket:= c_server_socket.create_server_socket('server',
            c_cassini_spy_server_client_socket);
        m_c_server_socket.m_on_after_accept:= handle_accept;
      end// create_cassini_spy

  • here the socket starts listening to IE:

    procedure c_cassini_spy.start_cassini_spy(p_ie_portInteger);
      begin
        with m_c_server_socket do
        begin
          m_trace_socket:= m_trace_cassini_spy;

          wsa_startup;
          create_win_socket;
          wsa_select;
          do_bind_win_socket(p_ie_port);
          do_listen_to_client(k_default_listen_queue_size)
        end// with m_c_server_socket
      end// start_cassini_spy

  • when IE sends data, the Server Socket spins-off a Server Client Socket:

    procedure c_cassini_spy.handle_accept(p_c_server_socketc_server_socket;
        p_c_server_client_socketc_server_client_socket);
      begin
        // -- use the same Memo2 display
        with (p_c_server_client_socket as c_cassini_spy_server_client_socketdo
        begin
          m_cassini_port:= m_cassini_port;
          m_on_display_cassini_spy_event:= m_on_display_cassini_spy_event;
        end;

        // -- feed back to the caller
        if Assigned(m_on_accept_tcp_cassini_spy_socket)
          then m_on_accept_tcp_cassini_spy_socket(Self);
      end// handle_accept




3.5 - The main form

The main form simply
  • creates the Spy Server Socket:

    var g_c_cassini_spyc_cassini_spyNil;

    procedure TForm1.go_Click(SenderTObject);
      begin
        // -- free any previous spy
        g_c_cassini_spy.Free;

        g_c_cassini_spy:= c_cassini_spy.create_cassini_spy('cassini_spy',
            k_site_pathStrToInt(cassini_port_.Text));

        with g_c_cassini_spy do
        begin
          m_trace_cassini_spy:= True;
          start_cassini_spy(StrToInt(ie_port_.Text));
          m_on_accept_tcp_cassini_spy_socket:= handle_tcp_cassini_spy_accept;
          m_on_display_cassini_spy_event:= handle_cassini_spy_display;
        end;
      end// go_pane_lClick

  • and handle the callback to display the packets in a tMemo

    procedure TForm1.handle_cassini_spy_display(p_codeIntegerp_textString);
        // -- 1 from IE, 2 from CASSINI
      var l_spacesString;

      procedure do_add(p_textString);
        begin
          content_memo_.Lines.Add(l_spacesp_text);
          raw_content_memo_.Lines.Add(p_text);
        end// do_add

      var l_indexInteger;
          l_the_lineString;

      begin // handle_cassini_spy_display
        case p_code of
          1 : begin
                l_spaces:= '';
                do_add('');
                do_add(IntToStr(g_request_count)+ ' ================');
                Inc(g_request_count);

                l_spaces:= '    -> | ';
              end;
          2 : begin
                l_spaces:= '';
                do_add('');
                do_add('--------------------------------------');

                l_spaces:= ' <-    | ';
              end;
          else l_spaces:= '??';
        end// case

        l_the_line:= '';
        l_index:= 1;
        while l_index<= Length(p_textdo
          if p_text[l_index]= k_return
            then begin
                do_add(l_the_line);
                l_the_line:= '';
                Inc(l_index, 2);
              end
            else begin
                l_the_line:= l_the_linep_text[l_index];
                Inc(l_index);
              end;

        // -- flush
        if l_the_line<> ''
          then do_add(l_the_line);
      end// handle_cassini_spy_display





4 - Mini How To

4.1 - The .aspx application

The goal is to display the result of a simple multiplication. We build an .aspx page, with a simple calculator:
  • 2 TextBoxes where the user enters 2 values, a "calculate" Buttons which submits the input values, and a result TextBox.
  • the Button OnClick naturally computes the product


We explained elsewhere how to prepare the .aspx page. Nevertheless, without all the screen snapshots, here is how to proceed:
   start Delphi, select "New | ASP.NET Web application - Delphi for .NET"
   using "File | Save as" (or the project manager) rename the page "a_01_calculator"
   Delphi asks where to put the files and what the project name is

   enter the names. for instance:

image

and click "Ok"

   drop the 3 TextBox from the "Web Controls" tab of the Palette on the Form

Drop a Button, and create its Click handler. Compute the result of the multiplication in the handler. For instance:

procedure TWebForm1.Button1_Click(senderSystem.ObjecteSystem.EventArgs);
  var l_totalInteger;
  begin
    l_total:= Convert.ToInt32(Textbox1.Text)* Convert.ToInt32(TextBox2.Text);
    TextBox3.Text:= Convert.ToString(l_total);
  end;

Here is the content of the .aspx file (we added labels etc):

 
<%@ Page Language="c#" Debug="true"
  Codebehind="a_01_calculator.pas" AutoEventWireup="false"
  Inherits="a_01_calculator.TWebForm1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title></title>
  </head>
  <body ms_positioning="GridLayout">
    <form runat="server">
      <asp:TextBox id="TextBox1"
        style="Z-INDEX: 1; LEFT: 54px; POSITION: absolute; TOP: 62px"
        runat="server" width="67px"></asp:TextBox>
      <asp:TextBox id="TextBox2"
        style="Z-INDEX: 2; LEFT: 142px; POSITION: absolute; TOP: 62px"
        runat="server" width="75px"></asp:TextBox>
      <asp:TextBox id="TextBox3"
        style="Z-INDEX: 3; LEFT: 238px; POSITION: absolute; TOP: 62px"
        runat="server" width="91px"></asp:TextBox>
      <asp:Button id="Button1"
        style="Z-INDEX: 4; LEFT: 54px; POSITION: absolute; TOP: 102px"
        runat="server" text="multiply"></asp:Button>
      <asp:Label id="Label1"
        style="Z-INDEX: 5; LEFT: 54px; POSITION: absolute; TOP: 22px"
        runat="server">price</asp:Label>
      <asp:Label id="Label2"
        style="Z-INDEX: 6; LEFT: 126px; POSITION: absolute; TOP: 22px"
        runat="server" width="3px">x</asp:Label>
      <asp:Label id="Label3"
        style="Z-INDEX: 7; LEFT: 150px; POSITION: absolute; TOP: 22px"
        runat="server">quantity</asp:Label>
      <asp:Label id="Label4"
        style="Z-INDEX: 8; LEFT: 222px; POSITION: absolute; TOP: 22px"
        runat="server">=</asp:Label>
    </form>
  </body>
</html>



Then
   click "Run"
   Delphi saves the files, starts Cassini, and calls Internet Explorer with our page as an address.
   Cassini receives the request, compiles the .aspx and .pas, builds the .HTML and sends it back to Internet Explorer:

image

   enter two values, 15 and 3 for instance, and click "multiply"

   IE submits the values to CASSINI, which sends the answer back:

image



Thats the standard Delphi way of building ASP.NET applications. But what was exactly exchanged between Internet Explorer and Delphi during those steps ? Well, enters the CASSINI SPY !



4.2 - Using the CASSINI SPY

After the creation of the .ASPX and .PAS, there are 3 steps:
  • start CASSINI
  • start the spy
  • start IE and request the page


Start CASSINI:
   manually start up CASSINI by clicking on CassiniWebServer.Exe
   CASSINI presents a parameter dialog

image

   enter your application path, the port and the virtual path:

image

and click "Start"

   CASSINI is ready

image

   click "Start"

   CASSINI presents all the files in our development folder:

image



Start our CASSINI SPY
   click on p_cassini_spy.exe
   the spy is ready

image

   click "Go" to start the Server Socket


Start Internet Explorer:
   start IE and enter the URL of our page (on port 81):

image

   hit Enter

   the CASSINI SPY displays the IE -> CASSINI packet as well as the answer:

image



By copying the CASSINI SPY result to the ClipBoard, here is the full packet exchange:

 
0 ====================================== 405
-> | GET /_01_calculator/a_01_calculator.aspx HTTP/1.1
-> | Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg,
             application/x-shockwave-flash, */*
-> | Accept-Language: fr
-> | Accept-Encoding: gzip, deflate
-> | User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows
             NT 5.1; SV1; .NET CLR 1.1.4322)
-> | Host: localhost:81
-> | Connection: Keep-Alive
-> | Cookie: Name=the_cookie; ASP.NET_SessionId=hlmd5ti4pfwssz452iog15uh
-> |
-> |

-------------------------------------- 1533
<- | HTTP/1.1 200 OK
<- | Server: Cassini/1.0.0.0
<- | Date: Thu, 16 Feb 2006 18:02:04 GMT
<- | X-AspNet-Version: 1.1.4322
<- | Cache-Control: private
<- | Content-Type: text/html; charset=utf-8
<- | Content-Length: 1318
<- | Connection: Close
<- |
<- |
<- | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<- |
<- | <html>
<- | <head>
<- | <title></title>
<- | </head>
<- | <body ms_positioning="GridLayout">
<- | <form name="_ctl0" method="post" action="a_01_calculator.aspx" id="_ctl0">
<- | <input type="hidden" name="__VIEWSTATE"
             value="dDwtMTcyMDIwMDYzNzs7PnErGOMElmmKP3tC3Yl1ObO7Bo1L" />
<- |
<- | <input name="TextBox1" type="text" id="TextBox1"
             style="width:67px;Z-INDEX: 1; LEFT: 54px; POSITION: absolute; TOP: 62px" />
<- | <input name="TextBox2" type="text" id="TextBox2"
             style="width:75px;Z-INDEX: 2; LEFT: 142px; POSITION: absolute; TOP: 62px" />
<- | <input name="TextBox3" type="text" id="TextBox3"
             style="width:91px;Z-INDEX: 3; LEFT: 238px; POSITION: absolute; TOP: 62px" />
<- | <input type="submit" name="Button1" value="multiply" id="Button1"
             style="Z-INDEX: 4; LEFT: 54px; POSITION: absolute; TOP: 102px" />
<- | <span id="Label1" style="Z-INDEX: 5; LEFT: 54px; POSITION: absolute; TOP: 22px">
             price</span>
<- | <span id="Label2" style="width:3px;Z-INDEX: 6; LEFT: 126px; POSITION: absolute; TOP: 22px">
             x</span>
<- | <span id="Label3" style="Z-INDEX: 7; LEFT: 150px; POSITION: absolute; TOP: 22px">
             quantity</span>
<- | <span id="Label4" style="Z-INDEX: 8; LEFT: 222px; POSITION: absolute; TOP: 22px">
             =</span>
<- | </form>
<- | </body>
<- | </html>
<- |



And here is the result of sending over 15 x 3 and clicking "multiply" :

 
1 ====================================== 677
-> | POST /_01_calculator/a_01_calculator.aspx HTTP/1.1
-> | Accept: image/gif, image/x-xbitmap, image/jpeg,
             image/pjpeg, application/x-shockwave-flash, */*
-> | Referer: http://localhost:81/_01_calculator/a_01_calculator.aspx
-> | Accept-Language: fr
-> | Content-Type: application/x-www-form-urlencoded
-> | Accept-Encoding: gzip, deflate
-> | User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;
             SV1; .NET CLR 1.1.4322)
-> | Host: localhost:81
-> | Content-Length: 110
-> | Connection: Keep-Alive
-> | Cache-Control: no-cache
-> | Cookie: Name=the_cookie; ASP.NET_SessionId=hlmd5ti4pfwssz452iog15uh
-> |
-> | __VIEWSTATE=dDwtMTcyMDIwMDYzNzs7PnErGOMElmmKP3tC3Yl1ObO7Bo1L
             &TextBox1=15
             &TextBox2=3
             &TextBox3=
             &Button1=multiply

--------------------------------------215
<- | HTTP/1.1 200 OK
<- | Server: Cassini/1.0.0.0
<- | Date: Thu, 16 Feb 2006 18:08:10 GMT
<- | X-AspNet-Version: 1.1.4322
<- | Cache-Control: private
<- | Content-Type: text/html; charset=utf-8
<- | Content-Length: 1350
<- | Connection: Close
<- |
<- |
--------------------------------------1351
<- |
<- | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<- |
<- | <html>
<- | <head>
<- | <title></title>
<- | </head>
<- | <body ms_positioning="GridLayout">
<- | <form name="_ctl0" method="post" action="a_01_calculator.aspx"
             id="_ctl0">
<- | <input type="hidden" name="__VIEWSTATE"
             value="dDwtMTcyMDIwMDYzNzs7PnErGOMElmmKP3tC3Yl1ObO7Bo1L" />
<- |
<- | <input name="TextBox1" type="text" value="15" id="TextBox1"
             style="width:67px;Z-INDEX: 1; LEFT: 54px; POSITION: absolute; TOP: 62px" />
<- | <input name="TextBox2" type="text" value="3" id="TextBox2"
             style="width:75px;Z-INDEX: 2; LEFT: 142px; POSITION: absolute; TOP: 62px" />
<- | <input name="TextBox3" type="text" value="45" id="TextBox3"
             style="width:91px;Z-INDEX: 3; LEFT: 238px; POSITION: absolute; TOP: 62px" />
<- | <input type="submit" name="Button1" value="multiply"
             id="Button1" style="Z-INDEX: 4; LEFT: 54px; POSITION: absolute; TOP: 102px" />
<- | <span id="Label1" style="Z-INDEX: 5; LEFT: 54px;
             POSITION: absolute; TOP: 22px">price</span>
<- | <span id="Label2" style="width:3px;Z-INDEX: 6; LEFT: 126px;
             POSITION: absolute; TOP: 22px">x</span>
<- | <span id="Label3" style="Z-INDEX: 7; LEFT: 150px;
             POSITION: absolute; TOP: 22px">quantity</span>
<- | <span id="Label4" style="Z-INDEX: 8; LEFT: 222px;
             POSITION: absolute; TOP: 22px">=</span>
<- | </form>
<- | </body>
<- | </html>
<- |



Of particular interest are

  • the ViewState value
  • the fact that IE only sent back the values of the controls (this is also the case for CGI)
  • the labels are ALSO sent back (I believed only the values of the controls were sent back)



5 - Improvements

This utility was built in on day. We have the tool, and will use it in the our forthcoming ASP.NET tutorials.

To change this into an "industrial strength" tool would require the addition of some automatic invocation: when the developper clicks "Run", we should force Delphi to launch our tool, and the SPY in turn should start CASSINI.




6 - Download the Sources

Here are the source code files:

The .ZIP file(s) contain:

  • the main program (.DPR, .DOF, .RES), the main form (.PAS, .DFM), and any other auxiliary form
  • any .TXT for parameters, samples, test data
  • all units (.PAS) for units
Those .ZIP
  • are self-contained: you will not need any other product (unless expressly mentioned).
  • for Delphi 6 projects, can be used from any folder (the pathes are RELATIVE)
  • will not modify your PC in any way beyond the path where you placed the .ZIP (no registry changes, no path creation etc).
To use the .ZIP:
  • create or select any folder of your choice
  • unzip the downloaded file
  • using Delphi, compile and execute
To remove the .ZIP simply delete the folder.

The Pascal code uses the Alsacian notation, which prefixes identifier by program area: K_onstant, T_ype, G_lobal, L_ocal, P_arametre, F_unction, C_lasse etc. This notation is presented in the Alsacian Notation paper.



As usual:

  • please tell us at fcolibri@felix-colibri.com if you found some errors, mistakes, bugs, broken links or had some problem downloading the file. Resulting corrections will be helpful for other readers
  • we welcome any comment, criticism, enhancement, other sources or reference suggestion. Just send an e-mail to fcolibri@felix-colibri.com.
  • or more simply, enter your (anonymous or with your e-mail if you want an answer) comments below and clic the "send" button
    Name :
    E-mail :
    Comments * :
     

  • and if you liked this article, talk about this site to your fellow developpers, add a link to your links page ou mention our articles in your blog or newsgroup posts when relevant. That's the way we operate: the more traffic and Google references we get, the more articles we will write.



7 - References

You may look at:


8 - The author

Felix John COLIBRI works at the Pascal Institute. Starting with Pascal in 1979, he then became involved with Object Oriented Programming, Delphi, Sql, Tcp/Ip, Html, UML. Currently, he is mainly active in the area of custom software development (new projects, maintenance, audits, BDE migration, Delphi Xe_n migrations, refactoring), Delphi Consulting and Delph training. His web site features tutorials, technical papers about programming with full downloadable source code, and the description and calendar of forthcoming Delphi, FireBird, Tcp/IP, Web Services, OOP  /  UML, Design Patterns, Unit Testing training sessions.
Created: nov-05. Last updated: jul-15 - 98 articles, 131 .ZIP sources, 1012 figures
Copyright © Felix J. Colibri   http://www.felix-colibri.com 2004 - 2015. All rigths reserved
Back:    Home  Papers  Training  Delphi developments  Links  Download
the Pascal Institute

Felix J COLIBRI

+ Home
  + articles_with_sources
    + database
    + web_internet_sockets
      – tcp_ip_sniffer
      – socket_programming
      – socket_architecture
      – simple_web_server
      – simple_cgi_web_server
      – cgi_database_browser
      – whois
      – web_downloader
      – web_spider
      – rss_reader
      – news_message_tree
      – indy_news_reader
      – delphi_web_designer
      – intraweb_architecture
      – ajax_tutorial
      – bayesian_spam_filter
      + asp_net
        – delph_asp_net_portal
        – cassini_spy
        – asp_net_log_file
        – viewstate_viewer
        – master_pages
        – asp_net_20_databases
        – asp_net_20_security
    + oop_components
    + uml_design_patterns
    + debug_and_test
    + graphic
    + controls
    + colibri_utilities
    + colibri_helpers
    + delphi
    + firemonkey
    + compilers
  + delphi_training
  + delphi_developments
  + sweet_home
  – download_zip_sources
  + links
Contacts
Site Map
– search :

RSS feed  
Blog